﻿#region Using Statements
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using DirectZZT.Shared.Core;
#endregion

namespace DirectZZT.Core
{
    /// <summary>
    /// Manages the <see cref="Configuration"/> instances.
    /// </summary>
    public static class ConfigurationManager
    {
        private static Dictionary<string, Configuration> _instances;

        static ConfigurationManager()
        {
            _instances = new Dictionary<string, Configuration>();
        }

        /// <summary>
        /// Retrieves the <see cref="Configuration"/> instance for the given id.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static Configuration Get(string id)
        {
            id = id.ToUpperInvariant();
            if (!_instances.ContainsKey(id))
            {
                return null;
            }
            return _instances[id];
        }

        /// <summary>
        /// Registers a new <see cref="Configuration"/> wrapper for the .conf file under the given path.
        /// </summary>
        /// <param name="id">The id of the configuration to register this with.</param>
        /// <param name="path">The full path of the configuration file.</param>
        public static void Register(string id, string path)
        {
            id = id.ToUpperInvariant();
            Configuration configuration = new Configuration(id, path);
            configuration.Load();
            _instances[id] = configuration;
        }

        /// <summary>
        /// Saves all configuration data.
        /// </summary>
        public static void Shutdown()
        {
            foreach (var item in _instances)
            {
                item.Value.Save();
            }
            _instances.Clear();
            _instances = null;
        }
    }

    /// <summary>
    /// Stores the global game configuration.
    /// </summary>
    public sealed class Configuration
    {
        #region Fields

        private Dictionary<string, string> _configuration;
        private string _path;
        private bool _isModified;
        private string _id;

        #endregion

        #region Constructors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="path"></param>
        public Configuration(string id, string path)
        {
            _configuration = new Dictionary<string, string>();
            _id = id;

            if (!Path.IsPathRooted(path))
            {
                _path = Path.Combine(Assembly.GetExecutingAssembly().GetWorkingDirectory(), path);
            }
            else
            {
                _path = path;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Loads the configuration.
        /// </summary>
        public void Load()
        {
            if (!File.Exists(_path))
            {
                Logging.GetLogging().LogFormat(LoggingMessageType.Error, "Configuration", "", "Found no configuration file under '{0}'!", _path);
            }
            else
            {
                using (StreamReader reader = new StreamReader(_path))
                {
                    string line = null;
                    while ((line = reader.ReadLine()) != null)
                    {
                        line = line.Trim();
                        if (line.StartsWith("#") || line.Length == 0)
                        {
                            continue;
                        }
                        string[] tokens = line.Split('=');
                        _configuration[tokens[0]] = tokens[1];
                    }
                }
            }
        }

        /// <summary>
        /// Saves the configuration.
        /// </summary>
        public void Save()
        {
            if (!_isModified)
            {
                Logging.GetLogging().LogFormat(LoggingMessageType.Error, "Configuration", "", "Configuration '{0}' is not modified. No need to save.", _id);
            }
            else
            {
                using (StreamWriter writer = new StreamWriter(_path, false))
                {
                    foreach (var setting in _configuration)
                    {
                        writer.WriteLine("{0}={1}", setting.Key, setting.Value);
                    }
                }
            }
        }

        /// <summary>
        /// Returns the Boolean-stored value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public bool GetBoolean(string name, bool defaultValue)
        {
            if (_configuration.ContainsKey(name))
            {
                bool v = defaultValue;
                bool.TryParse(_configuration[name], out v);
                return v;
            }
            return defaultValue;
        }

        /// <summary>
        /// Returns the Int32-stored value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public int GetInt32(string name, int defaultValue)
        {
            if (_configuration.ContainsKey(name))
            {
                int v = defaultValue;
                int.TryParse(_configuration[name], out v);
                return v;
            }
            return defaultValue;
        }

        /// <summary>
        /// Returns the Single-stored value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public float GetSingle(string name, float defaultValue)
        {
            if (_configuration.ContainsKey(name))
            {
                float v = defaultValue;
                float.TryParse(_configuration[name], NumberStyles.Float, CultureInfo.InvariantCulture, out v);
                return v;
            }
            return defaultValue;
        }

        /// <summary>
        /// Returns the string-stored value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public string GetString(string name, string defaultValue)
        {
            if (_configuration.ContainsKey(name))
            {
                return _configuration[name];
            }
            return defaultValue;
        }

        /// <summary>
        /// Stores the Boolean value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetBoolean(string name, bool value)
        {
            _configuration[name] = value.ToString();
            _isModified = true;
        }

        /// <summary>
        /// Stores the Int32 value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetInt32(string name, int value)
        {
            _configuration[name] = value.ToString();
            _isModified = true;
        }

        /// <summary>
        /// Stores the Single value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetSingle(string name, float value)
        {
            _configuration[name] = value.ToString();
            _isModified = true;
        }

        /// <summary>
        /// Stores the String value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetString(string name, string value)
        {
            _configuration[name] = value.ToString();
            _isModified = true;
        }

        #endregion
    }
}
